#ifndef __LDX_CSCENENODECAMERAFPS_H_INCLUDE__
#define __LDX_CSCENENODECAMERAFPS_H_INCLUDE__
#include "LDXConfig.h"
#include "ICameraSceneNode.h"
#include "SViewFrustum.h"

namespace ldx
{
	namespace scene
	{

		class CCameraSceneNode :public ICameraSceneNode
		{
		public:
			//! constructor
			CCameraSceneNode(ISceneNode* parent, CSceneManager* mgr, int id,
				const mt::vec3f& position = mt::vec3f(0, 0, 0),
				const mt::vec3f& lookat = mt::vec3f(0, 0, 100));

			~CCameraSceneNode();

			//! Sets the projection matrix of the camera.
			virtual void setProjectionMatrix(const mt::mat4& projection, bool isOrthogonal = false);

			//! Gets the current projection matrix of the camera
			//! \return Returns the current projection matrix of the camera.
			virtual const mt::mat4& getProjectionMatrix() const;

			//! Gets the current view matrix of the camera
			//! \return Returns the current view matrix of the camera.
			virtual const mt::mat4& getViewMatrix() const;

			//! Sets a custom view matrix affector.
			/** \param affector: The affector matrix. */
			virtual void setViewMatrixAffector(const mt::mat4& affector);

			//! Gets the custom view matrix affector.
			virtual const mt::mat4& getViewMatrixAffector() const;

			//! It is possible to send mouse and key events to the camera. Most cameras
			//! may ignore this input, but camera scene nodes which are created for 
			//! example with scene::ISceneManager::addMayaCameraSceneNode or
			//! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input
			//! for changing their position, look at target or whatever. 
			virtual bool OnEvent(const SEvent& event);

			//! Sets the look at target of the camera
			/** If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
			then calling this will also change the camera's scene node rotation to match the target.
			\param pos: Look at target of the camera. */
			virtual void setTarget(const mt::vec3f& pos);

			//! Sets the rotation of the node.
			/** This only modifies the relative rotation of the node.
			If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
			then calling this will also change the camera's target to match the rotation.
			\param rotation New rotation of the node in degrees. */
			virtual void setRotation(const mt::vec3f& rotation);

			//! Gets the current look at target of the camera
			/** \return The current look at target of the camera */
			virtual const mt::vec3f& getTarget() const;

			//! Sets the up vector of the camera.
			//! \param pos: New upvector of the camera.
			virtual void setUpVector(const mt::vec3f& pos);

			//! Gets the up vector of the camera.
			//! \return Returns the up vector of the camera.
			virtual const mt::vec3f& getUpVector() const;

			//! Gets distance from the camera to the near plane.
			//! \return Value of the near plane of the camera.
			virtual float getNearValue() const;

			//! Gets the distance from the camera to the far plane.
			//! \return Value of the far plane of the camera.
			virtual float getFarValue() const;

			//! Get the aspect ratio of the camera.
			//! \return The aspect ratio of the camera.
			virtual float getAspectRatio() const;

			//! Gets the field of view of the camera.
			//! \return Field of view of the camera
			virtual float getFOV() const;

			//! Sets the value of the near clipping plane. (default: 1.0f)
			virtual void setNearValue(float zn);

			//! Sets the value of the far clipping plane (default: 2000.0f)
			virtual void setFarValue(float zf);

			//! Sets the aspect ratio (default: 4.0f / 3.0f)
			virtual void setAspectRatio(float aspect);

			//! Sets the field of view (Default: PI / 3.5f)
			virtual void setFOV(float fovy);

			//! PreRender event
			virtual void OnRegisterSceneNode();

			//! Render
			virtual void render();

			//! Returns the axis aligned bounding box of this node
			virtual const mt::aabbox3df& getBoundingBox() const;

			//! Returns the view area. Sometimes needed by bsp or lod render nodes.
			virtual const SViewFrustum* getViewFrustum() const;

			//! Disables or enables the camera to get key or mouse inputs.
			//! If this is set to true, the camera will respond to key inputs
			//! otherwise not.
			virtual void setInputReceiverEnabled(bool enabled);

			//! Returns if the input receiver of the camera is currently enabled.
			virtual bool isInputReceiverEnabled() const;

			//! Returns type of the scene node
			virtual ESCENE_NODE_TYPE getType() const { return ESNT_CAMERA; }

			//! Binds the camera scene node's rotation to its target position and vice vera, or unbinds them.
			virtual void bindTargetAndRotation(bool bound);

			//! Queries if the camera scene node's rotation and its target position are bound together.
			virtual bool getTargetAndRotationBinding(void) const;

		private:

			void updateViewMatrix();
			void updateProjectionMatrix();
			void updateCameraMatrix();


			mt::vec3f DefaultLookAt;
			mt::vec3f DefaultEyeUp;

			mt::vec3f Target;
			mt::vec3f UpVector;

			float Fovy;	// Field of view, in radians. 
			float Aspect;	// Aspect ratio. 
			float ZNear;	// value of the near view-plane. 
			float ZFar;	// Z-value of the far view-plane.

			SViewFrustum ViewArea;
			mt::mat4 Affector;

			bool InputReceiverEnabled;
			bool TargetAndRotationAreBound;

		};
	}
}


#endif//! __LDX_CSCENENODECAMERAFPS_H_INCLUDE__